package servidorIndice.controlador;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;

/**
 * Clase que reperesenta el servidor indice
 * @author Jorge Hernán Londoño Echeverri narzyx@gmail.com Hayner Benavides Moreno hayner2005@gmail.com
 */
public class ProcesarServidorIndice extends Thread{
    private Socket cliente;
    private Registro registro;
    private int indice;
    private int estado;
    private ArrayList<String> bitacora;

    /**
     * Contructor
     * @param cliente
     * @param indice
     */
    public ProcesarServidorIndice(Socket cliente, int indice) {
        
        this.setCliente(cliente);
        this.setIndice(indice);
        this.setEstado(0);
        bitacora = new ArrayList<String>();
    }
    /**
     * Mpetodo Run oara ejecutar los hilos
     */
    public void run() {
        try {
            this.procesarCliente();
        } catch (Exception e) {
            System.out.println("Se ha generado un error dentro del run: "+e.getMessage());
        }
    }

    public void procesarCliente() throws Exception{

        try {
            PrintWriter out = new PrintWriter(cliente.getOutputStream(),true);
            BufferedReader buffr = new BufferedReader(new InputStreamReader(cliente.getInputStream()));
            String mensaje = "";
            while((mensaje = buffr.readLine()) != null) {
                System.out.println("llego "+mensaje);
                String[] fragmentosMensaje = procesarMensaje(mensaje);
                
                if(fragmentosMensaje[0].trim().equals("REGISTRAR")) {
                    registro = new Registro(fragmentosMensaje[1], fragmentosMensaje[2]);
                    registro.setIndice(indice+"");
                    setEstado(1);
                    if(insertarADb()){
                        out.println("S");
                        insertarValorEnBitacora("Se ha conectado un nuevo cliente con IP: "+registro.getIp()+"\n con el indice "+registro.getIndice());
                    }
                    else{
                        out.println("N");
                        insertarValorEnBitacora("No se logro la conexión de un nuevo cliente con IP: "+registro.getIp());
                    }

                } else if(fragmentosMensaje[0].trim().equals("LISTAR")) {
                    out.println(construirLista(listar()));
                } else {
                   // System.out.println("Operación no valida");
                    out.println("operacion invalida");
                }
                
            }
            System.out.println("Se tiene el proceso "+getIndice());
            insertarValorEnBitacora("Se ha terminado la conexión del proceso "+getIndice());
            desconectar();
        }
        catch (SocketException se) {
            System.out.println("Se ha terminado la conexión del proceso "+getIndice());
            insertarValorEnBitacora("Se ha terminado la conexión del proceso "+getIndice());
            //e.printStackTrace();
            //throw new Exception("Se ha presentando un error en el método de procesar cliente", se);
        }
        catch (Exception e) {
            e.printStackTrace();
            throw new Exception("Se ha presentando un error en el método de procesar cliente", e);
        }
        finally{
            cliente.close();
        }
    }
    
    public void terminar(){
         try{
            cliente.close();
            insertarValorEnBitacora("Se ha desconectado el cliente con indice: "+registro.getIndice()+"\n  e IP: "+registro.getIp());
         }
         catch(Exception e){
             System.out.println("error al matar el socket");
         }
    }

    /**
     * Método que por medio de un expresión regular
     * obtiene el mensaje y lo procesa por medio de los
     * fragmentos, determinado por el separador |
     * @param mensaje
     * @return
     */
    public String[] procesarMensaje(String mensaje) {
        String[] fragmentos = mensaje.split("\\|");
        return fragmentos;
    }

    /**
     * Método que cierra la conexión de socket
     * y elimina los registros que se encuentren en
     * la base de datos
     */
    public void desconectar() {
        RegistrosControlador controlador = new RegistrosControlador();
            if(controlador.init("sqlite")){
                controlador.eliminarRegistro(indice);
            }
            controlador.cerrar();
    }

    /**
     * Método que llama al insertar un registro o actualizarolo
     * por medio del objeto Registro
     */
    public boolean insertarADb(){
        RegistrosControlador controlador = new RegistrosControlador();
        if(controlador.init("sqlite")){
            if(!controlador.isDireccionPuertoDuplicada(this.registro.getIp(), this.registro.getPuerto())){
                if(controlador.isRegistro(indice+"")){
                    controlador.actualizarRegistro(registro);
                }
                else{
                    controlador.insertarRegistro(registro);
                }
                return true;
            }
            else
                return false;

        }
        controlador.cerrar();
        return false;
    }

    /**
     * Método que obtiene la lista de registros que se encuentran
     * en base de datos
     * @return ArrayList<Registro>
     */
    public ArrayList<Registro> listar(){
        ArrayList<Registro> lista = new ArrayList<Registro>();
        RegistrosControlador controlador = new RegistrosControlador();

        if(controlador.init("sqlite")){
            lista = controlador.buscarExcepto(indice+"");
        }
        controlador.cerrar();
        return lista;
    }

    /**
     *
     * @param lista
     * @return String
     */
    public String construirLista(ArrayList<Registro> lista){
        String resultado="";
        for(int i=0; i <lista.size();i++){
            Registro registro = lista.get(i);
            if(i!=0){
                resultado +="@";
            }
            resultado += registro.getIp()+"|"+registro.getPuerto();

        }
        System.out.println(resultado);
        return resultado;
    }

    public Socket getCliente() {
        return cliente;
    }

    public void setCliente(Socket cliente) {
        this.cliente = cliente;
    }

    public Registro getRegistro() {
        return registro;
    }

    public void setRegistro(Registro registro) {
        this.registro = registro;
    }

    public int getIndice() {
        return indice;
    }

    public void setIndice(int indice) {
        this.indice = indice;
    }

    public int getEstado() {
        return estado;
    }

    public void setEstado(int estado) {
        this.estado = estado;
    }

    public ArrayList<String> getBitacora() {
        return bitacora;
    }

    public void setBitacora(ArrayList<String> bitacora) {
        this.bitacora = bitacora;
    }

    public void insertarValorEnBitacora(String valor){
        this.bitacora.add(valor);
    }

    public void limpiarBitacora(){
        this.bitacora.clear();
    }


}
